#pragma once
#include "BaseQueue.h"

template <typename T>
class ArrayQueue : public BaseQueue<T>
{
private :
	const int m_nSize;
	T* m_oQueue;
	int m_nLastIndex;

	bool shiftToRight();
public :
	ArrayQueue(int a_nMaxSize);
	~ArrayQueue();

	virtual void offer(T a_oData);
	virtual T poll();
	virtual T peek();
	virtual bool canOffer();
	virtual bool canPoll();
	virtual int getDataCount();

};

template <typename T>
ArrayQueue<T>::ArrayQueue(int a_nSize) : m_nSize(a_nSize)
{
	this->m_oQueue = new T[a_nSize];
	this->m_nLastIndex = -1;
}

template <typename T>
ArrayQueue<T>::~ArrayQueue()
{
	this->m_nLastIndex = -1;
	delete[] this->m_oQueue;
}

template <typename T>
bool ArrayQueue<T>::shiftToRight() {

	if(m_nSize == m_nLastIndex + 1) {
		return false;
	}

	T prevData = m_oQueue[0];

	for(int i = 1; i <= m_nLastIndex + 1; i++) {
		
		T backupData = m_oQueue[i];
		m_oQueue[i] = prevData;
		prevData = backupData;
	}

	m_nLastIndex++;
	return true;
}

template <typename T>
void ArrayQueue<T>::offer(T a_oData) {

	if(canOffer() == false) {
		throw DSFullFilledException();
	}

	if(getDataCount() > 0) {
		if(shiftToRight() == false) {
			throw DSFullFilledException();
		}
		m_oQueue[0] = a_oData;
	}
	else {
		m_nLastIndex++;
		m_oQueue[0] = a_oData;
	}
	
}

template <typename T>
T ArrayQueue<T>::poll() {

	if(canPoll() == false) {
		throw DSEmptyException();
	}

	T data = m_oQueue[m_nLastIndex--];
	return data;
}

template <typename T>
T ArrayQueue<T>::peek() {

	if(canPoll() == false) {
		throw DSEmptyException();
	}

	T data = m_oQueue[m_nLastIndex];
	return data;
}

template <typename T>
bool ArrayQueue<T>::canOffer() {
	int maxIndex = m_nSize - 1;
	if(m_nLastIndex == maxIndex) {
		return false;
	}

	return true;
}

template <typename T>
bool ArrayQueue<T>::canPoll() {

	if(m_nLastIndex < 0) {
		return false;
	}

	return true;
}

template <typename T>
int ArrayQueue<T>::getDataCount() {

	return m_nLastIndex + 1;
}